package pira.parser.xml.dblp;

import java.io.CharArrayWriter;
import java.io.FileReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.neo4j.graphdb.RelationshipType;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import pira.db.ui.GraphDBUI;
import pira.elements.Author;
import pira.elements.Paper;
import pira.utils.Log;


public class XMLFilesReader extends DefaultHandler{
	
	public static final String XMLFILE= "/home/liang/Downloads/dblp.xml";
	public static final int LIMITPAPERNUM = 8000;
	
	public static final String ARTICLE = "article";
	public static final String INPROCEEDINGS = "inproceedings";
	public static final String PROCEEDINGS = "proceedings";
	public static final String BOOK = "book";
	public static final String INCOLLECTION = "incollection";
	public static final String PHDTHESIS = "phdthesis";
	public static final String MASTERSTHESIS = "mastersthesis";
	public static final String WWW= "www";
	
	public int[] boundary= {10, 100, 1000, 2000, 4000, 8000};
	private long startTime;
	private float[] times;
	public int boundaryIndex= 0;
	public Log log;
	private long dbTime;
	
	private static int paperNum;
	private static int authorNum;
	
	private int[] classification;
	
	private GraphDBUI gdbui;
	
	public enum MyRelationshipTypes implements RelationshipType {
        WRITE,
        WRITTEN_BY,
        CITE,
        CITED_BY,
        PERSON_CITE,
        PERSON_CITED_BY,
        LIEN,
        CO
    }

	// record last paper 
	private Paper lastPaper;
	
	// current paper object reference
	private Paper currentPaper;

	// current author object reference
	private Author currentAuthor;
	
	// use to gather data from characters SAX
	private CharArrayWriter contents = new CharArrayWriter();

	public XMLFilesReader() {
		this.currentPaper= null;
		this.currentAuthor= null;
		this.lastPaper= null;
		
		log= new Log("XML2DB.log");
		startTime= 0;
		times= new float[6];
		classification= new int[8];
		dbTime= 0;
		
		gdbui= new GraphDBUI();
	}
	
	
	
	//	override the DefaultHandler class to block the method of SAX accident
	// 	read the org.xml.sax.ContentHandler for more

	public void startElement(String namespaceURI, String localName,
			String qName, Attributes attr) throws SAXException {

		contents.reset();

		// new code here, judge the elements' label
		if (localName.equals(ARTICLE)||localName.equals(INPROCEEDINGS)
				||localName.equals(PROCEEDINGS)||localName.equals(BOOK)
				||localName.equals(INCOLLECTION)||localName.equals(PHDTHESIS)
				||localName.equals(MASTERSTHESIS)||localName.equals(WWW)) {
			currentPaper= new Paper();
			currentPaper.type= localName;
			
			if (attr.getLength() > 0) {
				DateFormat df= new SimpleDateFormat("yyyy-MM-dd");
				try {
					Date ndate= df.parse(attr.getValue(0));
					currentPaper.mdate= ndate;
				} catch (java.text.ParseException e) {
					e.printStackTrace();
					currentPaper.mdate= null;
				}
				
				currentPaper.key= attr.getValue(1);
			}
		}
		
	}


	public void endElement(String namespaceURI, String localName, String qName)
			throws SAXException {
		
		// my elements
		if (localName.equals("author")) {
			String fullName= contents.toString();
			currentAuthor= new Author(fullName);
			
			// add to author vector
			long timeBefore= System.currentTimeMillis();
			this.addAuthor(currentAuthor);
			long timePassed= System.currentTimeMillis() - timeBefore;
			this.dbTime+=timePassed;
			// add to co-author list of the paper
			currentPaper.getAuthors().add(currentAuthor);
		}
		if (localName.equals("editor")) 
			currentPaper.editor= contents.toString();
		
		if (localName.equals("title")) 
			currentPaper.setTitle(contents.toString());
		
		if (localName.equals("publisher"))
			currentPaper.publisher= contents.toString();
		
		if (localName.equals("bookTitle")) 
			currentPaper.bookTitle= contents.toString();
		
		if (localName.equals("cdrom"))
			currentPaper.cdrom= contents.toString();
		
		if (localName.equals("pages")) 
			currentPaper.pages= contents.toString();

		if (localName.equals("url"))
			currentPaper.paperURL= contents.toString();
		
		if (localName.equals("isbn"))
			currentPaper.isbn= contents.toString();
		
		if (localName.equals("cite"))
			currentPaper.cite= contents.toString();
		
		if (localName.equals("series"))
			currentPaper.series= contents.toString();
		
		if (localName.equals("ee"))
			currentPaper.ee= contents.toString();
		
		if (localName.equals("crossref"))
			currentPaper.crossref= contents.toString();
		
		if (localName.equals(ARTICLE)||localName.equals(INPROCEEDINGS)
				||localName.equals(PROCEEDINGS)||localName.equals(BOOK)
				||localName.equals(INCOLLECTION)||localName.equals(PHDTHESIS)
				||localName.equals(MASTERSTHESIS)||localName.equals(WWW)) {
			
			paperNum++;
			System.out.println("Paper numbers: " + paperNum);
			
			if (localName.equals(ARTICLE))
				classification[0]++;
			else if (localName.equals(INPROCEEDINGS))
				classification[1]++;
			else if (localName.equals(PROCEEDINGS))
				classification[2]++;
			else if (localName.equals(BOOK))
				classification[3]++;
			else if (localName.equals(INCOLLECTION))
				classification[4]++;
			else if (localName.equals(PHDTHESIS))
				classification[5]++;
			else if (localName.equals(MASTERSTHESIS))
				classification[6]++;
			else
				classification[7]++;
			
			long timeBefore= System.currentTimeMillis();
			this.addPaper(currentPaper);
			long timePassed= System.currentTimeMillis() - timeBefore;
			this.dbTime+=timePassed;
			
			if (lastPaper != null) {
				gdbui.addLien(currentPaper, lastPaper);
			}
			lastPaper= currentPaper;
			
			if (paperNum == boundary[boundaryIndex]) {
				long currentTime= System.currentTimeMillis();
				times[boundaryIndex]= (float)(currentTime-startTime)/1000;
				String str= "Parse " + paperNum + " papers.\n " +
						"After " + times[boundaryIndex] + " seconds.\n" +
						"Database time is : " + (float)dbTime/1000 + " seconds.\n" +
						"Classification:" +
						ARTICLE + " : " + classification[0] + "\t" +
						(float)classification[0]/paperNum * 100 + "%\n" +
						INPROCEEDINGS + " : " + classification[1] + "\t" +
						(float)classification[1]/paperNum * 100+ "%\n" + 
						PROCEEDINGS + " : " + classification[2]	+ "\t" +
						(float)classification[2]/paperNum * 100+ "%\n" +
						BOOK + " : " + classification[3] + "\t" +
						(float)classification[3]/paperNum * 100+ "%\n" + 
						INCOLLECTION + " : " + classification[4] + "\t" + 
						(float)classification[4]/paperNum * 100+ "%\n" +
						PHDTHESIS + " : " + classification[5] + "\t" +
						(float)classification[5]/paperNum * 100+ "%\n" + 
						MASTERSTHESIS + " : " + classification[6] + "\t" +
						(float)classification[6]/paperNum * 100+ "%\n" +
						WWW + " : " + classification[7] + "\t" +
						(float)classification[7]/paperNum * 100+ "%\n\n";
				log.write(str);
				System.out.println(str);
				
				boundaryIndex++;
			}
			
			if (paperNum == LIMITPAPERNUM) {
				System.out.println("==============Parser XML End============");
				System.out.println("Parse " + paperNum + " papers.");
				System.out.println("Parse " + authorNum + " authors.");
				System.out.println("========================================");
				System.out.println();
				
				addExternalPaper();
				shutDown();
			}
		}
	}

	public void characters(char[] ch, int start, int length)
			throws SAXException {
		contents.write(ch, start, length);
	}

	public void XMLtoDB(String fileName) {
System.out.println("Example:");
		this.startTime= System.currentTimeMillis();
		String str= "Parse program start at " + startTime + "\n";
		log.write(str);
		
		try {
			// create SAX 2 parser
			XMLReader xr = XMLReaderFactory.createXMLReader();

			// install ContentHandler．．．
			xr.setContentHandler(this);

			// parse file
			xr.parse(new InputSource(new FileReader(fileName)));
		} catch (IllegalStateException e1) {
			System.out.println("Index has been shut down.");
			System.out.println("Transformer from XML to DB end.");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private long addPaper(Paper paper) {
		if (gdbui.findPaper(paper) == null)
			return gdbui.addPaperToDB(paper);
		else
			// paper already in database
			return -1;
	}
	
	private long addAuthor(Author author) {
		if (gdbui.findAuthor(author) == null) {
			System.out.println("Author numbers: " + (++authorNum));
			return gdbui.addAuthorToDB(author);
		} else
			// author already in database
			return -1;
	}
	
	private void addExternalPaper() {
		// create a virtual node that represent the external citation
		Paper virtualPaper= new Paper();
		virtualPaper.setTitle(GraphDBUI.EXTERNAL);
		virtualPaper.type= GraphDBUI.EXTERNAL;
		addPaper(virtualPaper);
		gdbui.addLien(virtualPaper, lastPaper);
	}
	
	public void shutDown() {
		long timePassed= System.currentTimeMillis() - startTime;
		String str= "Parse program end after " + (float)timePassed/1000 + "seconds.\n";
		System.out.print(str);
		log.write(str);
		
		this.log.close();
		gdbui.shutDown();
	}
	
	public static void main(String[] args) {
		XMLFilesReader trans= new XMLFilesReader();
//		trans.XMLtoDB("XMLFiles/example.xml");
		trans.XMLtoDB(XMLFILE);
	}
}
